package com.ubs.lingua.buildtool.cs;

import java.util.Scanner;

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Launch the Engine from a variety of sources, either through a main() or invoked through Apache Daemon.
 * Implementing the Daemon interface is not required for Windows but is for Linux.
 */
public class EngineLauncher implements Daemon {

    private static final Log LOG = LogFactory.getLog(EngineLauncher.class);

    public static final String START_COMMAND = "start";
    public static final String STOP_COMMAND = "stop";

    private static Engine engine = null;

    private static EngineLauncher instance = new EngineLauncher();

    /**
     * The Java entry point.
     * @param args Command line arguments, all ignored.
     */
    public static void main(final String[] args) {
        System.out.printf("\n\nStarting service. Enter '%s' to halt:\n\n", STOP_COMMAND); // NOPMD (SystemPrintln): this method is for console execution
        instance.initialize();
        final Scanner scanner = new Scanner(System.in);
        // wait until receive stop command from keyboard
        while (!scanner.nextLine().equalsIgnoreCase(STOP_COMMAND)) {
            // do nothing
        }

        if (!engine.isStopped()) {
            instance.terminate();
        }

    }

    /**
     * Static methods called by prunsrv to start/stop the Windows service.
     * Pass the argument {@link #START_COMMAND} to start the service, and pass {@link #STOP_COMMAND} to stop the service.
     * @param args Arguments from prunsrv command line
     **/
    public static void windowsService(final String args[]) {
        String cmd = START_COMMAND;
        if (args.length > 0) {
            cmd = args[0];
        }

        if (START_COMMAND.equals(cmd)) {
            instance.windowsStart();
        }
        else {
            instance.windowsStop();
        }
    }

    public void windowsStart() {
        LOG.debug("windowsStart called");
        initialize();
        while (!engine.isStopped()) {
            // don't return until stopped
            synchronized (this) {
                try {
                    this.wait(60000); // wait 1 minute and check if stopped
                }
                catch (InterruptedException ie) {
                    // nothing to do
                }
            }
        }
    }

    public void windowsStop() {
        LOG.debug("windowsStop called");
        terminate();
        synchronized (this) {
            // Stop the start loop. 
            this.notify(); // FINDBUGS (NN_NAKED_NOTIFY): The change to mutable object state have taken place in the terminate method.
        }
    }

    @Override
    public void init(final DaemonContext arg0) throws Exception {
        LOG.debug("Daemon init");
    }

    @Override
    public void start() {
        LOG.debug("Daemon start");
        initialize();
    }

    @Override
    public void stop() {
        LOG.debug("Daemon stop");
        terminate();
    }

    @Override
    public void destroy() {
        LOG.debug("Daemon destroy");
    }

    /**
     * Do the work of starting the engine
     */
    private void initialize() {
        synchronized (this) {
            if (engine == null) {
                LOG.info("Starting the Engine");
                final CsBuildAgentEngine csBuildAgent = new CsBuildAgentEngine();
                engine = csBuildAgent;
                new Thread(csBuildAgent).start();
            }
        }
    }

    /**
     * Cleanly stop the engine.
     */
    public void terminate() {
        if (engine != null) {
            LOG.info("Stopping the Engine");
            engine.stop();
            LOG.info("Engine stopped");
        }
    }
}
